using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using SqlSugar;

namespace Admin.NET.Application.Service.Report;

/// <summary>
/// 出入库流水报表服务
/// </summary>
[ApiDescriptionSettings("Report", Name = "inOutFlow", Order = 900)]
[Route("api/report/inOutFlow")]
[AllowAnonymous]
public class InOutFlowReportService : IDynamicApiController, ITransient
{
	private readonly ISqlSugarClient _sqlSugarClient;

	public InOutFlowReportService(ISqlSugarClient sqlSugarClient)
	{
		_sqlSugarClient = sqlSugarClient;
	}

	/// <summary>
	/// 出入库流水分页查询（按时间范围、物品类别、操作员等筛选）
	/// </summary>
[HttpPost("page")]
public async Task<object> Page([FromBody] GetInOutFlowInput input)
	{
	DateTime? start = input.StartTime?.Date;
	DateTime? end = input.EndTime?.Date;
	if (end != null)
	{
		end = end.Value.AddDays(1).AddTicks(-1);
	}

		// 入库记录（含库位、部门、单价等）
		var inboundQuery = _sqlSugarClient.Queryable<Sysinstockorder>()
			.LeftJoin<WarePlaceModel>((i, wp) => i.WarePlaceId == wp.Id)
			.LeftJoin<SysOrg>((i, wp, org) => i.OrgId == org.Id)
			.WhereIF(start != null, (i, wp, org) => i.InDate >= start)
			.WhereIF(end != null, (i, wp, org) => i.InDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), (i, wp, org) => i.GoodsName!.Contains(input.GoodsOrCategory!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.OperatorName), (i, wp, org) => i.AgentName!.Contains(input.OperatorName!))
			.Select((i, wp, org) => new InOutFlowRowOutput
			{
				BizType = "入库",
				BillNo = i.Code,
				BizTime = i.InDate,
				GoodsName = i.GoodsName,
				WarehouseName = i.WarehouseName,
				WarePlaceName = wp.WarePlaceName,
				Quantity = i.InQuantity,
				Amount = i.WarehouseAmount,
				InQuantity = i.InQuantity,
				InAmount = i.WarehouseAmount,
				InUnitPrice = i.InQuantity > 0 ? i.WarehouseAmount / SqlFunc.ToDecimal(i.InQuantity) : (decimal?)null,
				OperatorName = i.AgentName,
				MakerName = i.CreateUserName,
				DeptName = org.Name,
				MakeTime = i.CreateTime,
				AuditorName = i.UpdateUserName,
				AuditTime = i.UpdateTime,
				Remark = i.Remark
			});

		// 出库记录（含库位、部门、单价等）
		var outboundQuery = _sqlSugarClient.Queryable<Sysoutstockorder>()
			.LeftJoin<WarePlaceModel>((o, wp) => o.WarePlaceId == wp.Id)
			.LeftJoin<SysOrg>((o, wp, org) => o.OrgId == org.Id)
			.WhereIF(start != null, (o, wp, org) => o.OutDate >= start)
			.WhereIF(end != null, (o, wp, org) => o.OutDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), (o, wp, org) => o.GoodsName!.Contains(input.GoodsOrCategory!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.OperatorName), (o, wp, org) => o.ContactPerson!.Contains(input.OperatorName!))
			.Select((o, wp, org) => new InOutFlowRowOutput
			{
				BizType = "出库",
				BillNo = o.Code,
				BizTime = o.OutDate,
				GoodsName = o.GoodsName,
				WarehouseName = o.WarehouseName,
				WarePlaceName = wp.WarePlaceName,
				Quantity = o.OutQuantity,
				Amount = o.OutbouAmount,
				OutQuantity = o.OutQuantity,
				OutAmount = o.OutbouAmount,
				OutUnitPrice = o.OutQuantity > 0 ? o.OutbouAmount / SqlFunc.ToDecimal(o.OutQuantity) : (decimal?)null,
				OperatorName = o.ContactPerson,
				MakerName = o.CreateUserName,
				DeptName = org.Name,
				MakeTime = o.CreateTime,
				AuditorName = o.UpdateUserName,
				AuditTime = o.UpdateTime,
				Remark = o.Remark
			});

		// 合并并内存分页（避免不同表结构导致的 UnionAll 扩展不可用问题）
		var inboundList = await inboundQuery.ToListAsync();
		var outboundList = await outboundQuery.ToListAsync();
		var all = inboundList.Concat(outboundList)
			.OrderByDescending(x => x.BizTime);

		var total = all.Count();
		var items = all
			.Skip((input.Page - 1) * input.PageSize)
			.Take(input.PageSize)
			.ToList();

		return new
		{
			Items = items,
			Total = total,
			Page = input.Page,
			PageSize = input.PageSize
		};
	}

	/// <summary>
	/// 获取统计卡片
	/// </summary>
[HttpPost("stats")]
public async Task<InOutFlowStatsOutput> GetStats([FromBody] GetInOutFlowInput input)
	{
	DateTime? start = input.StartTime?.Date;
	DateTime? end = input.EndTime?.Date;
	if (end != null)
	{
		end = end.Value.AddDays(1).AddTicks(-1);
	}

		var inbound = _sqlSugarClient.Queryable<Sysinstockorder>()
			.WhereIF(start != null, x => x.InDate >= start)
			.WhereIF(end != null, x => x.InDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.OperatorName), x => x.AgentName!.Contains(input.OperatorName!));

		var outbound = _sqlSugarClient.Queryable<Sysoutstockorder>()
			.WhereIF(start != null, x => x.OutDate >= start)
			.WhereIF(end != null, x => x.OutDate <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.OperatorName), x => x.ContactPerson!.Contains(input.OperatorName!));

		return new InOutFlowStatsOutput
		{
			InboundQuantity = await inbound.SumAsync(x => x.InQuantity),
			OutboundQuantity = await outbound.SumAsync(x => x.OutQuantity),
			InboundAmount = await inbound.SumAsync(x => x.WarehouseAmount),
			OutboundAmount = await outbound.SumAsync(x => x.OutbouAmount)
		};
	}
}

public class GetInOutFlowInput
{
	public DateTime? StartTime { get; set; }
	public DateTime? EndTime { get; set; }
	public string? GoodsOrCategory { get; set; }
	public string? OperatorName { get; set; }
	public int Page { get; set; } = 1;
	public int PageSize { get; set; } = 10;
}

public class InOutFlowRowOutput
{
	public string BizType { get; set; } = "";
	public string? BillNo { get; set; }
	public DateTime BizTime { get; set; }
	public string? GoodsName { get; set; }
	public string? WarehouseName { get; set; }
	public string? WarePlaceName { get; set; }
	public decimal Quantity { get; set; }
	public decimal Amount { get; set; }
	public decimal? InUnitPrice { get; set; }
	public decimal? InQuantity { get; set; }
	public decimal? InAmount { get; set; }
	public decimal? OutUnitPrice { get; set; }
	public decimal? OutQuantity { get; set; }
	public decimal? OutAmount { get; set; }
	public string? OperatorName { get; set; }
	public string? MakerName { get; set; }
	public string? DeptName { get; set; }
	public DateTime? MakeTime { get; set; }
	public string? AuditorName { get; set; }
	public DateTime? AuditTime { get; set; }
	public string? Remark { get; set; }
}

public class InOutFlowStatsOutput
{
	public decimal InboundQuantity { get; set; }
	public decimal OutboundQuantity { get; set; }
	public decimal InboundAmount { get; set; }
	public decimal OutboundAmount { get; set; }
}

internal static class HttpContextUtilities
{
	private static readonly AsyncLocal<Dictionary<string, object>> _items = new AsyncLocal<Dictionary<string, object>>();

	public static void SetItem(string key, object value)
	{
		_items.Value ??= new Dictionary<string, object>();
		_items.Value[key] = value;
	}

	public static T? GetItem<T>(string key)
	{
		if (_items.Value != null && _items.Value.TryGetValue(key, out var val))
		{
			return (T)val;
		}
		return default;
	}
}


